package com.size.mall.service.impl;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.size.mall.mallapi.entity.PmsSkuAttrValue;
import com.size.mall.mallapi.entity.PmsSkuInfo;
import com.size.mall.mallapi.service.PmsSkuAttrValueService;
import com.size.mall.mallapi.service.PmsSkuInfoService;
import com.size.mall.mapper.PmsSkuInfoMapper;
import com.size.mall.util.RedisUtil;
import org.apache.ibatis.jdbc.Null;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import redis.clients.jedis.Jedis;

import javax.swing.text.html.Option;
import java.math.BigDecimal;
import java.util.List;
import java.util.Optional;
import java.util.UUID;

@Service
public class PmsSkuInfoServiceImpl extends ServiceImpl<PmsSkuInfoMapper, PmsSkuInfo> implements
        PmsSkuInfoService {


    @Cacheable(value = {"skuInfo"}, unless = "#result==null")
    @Override
    public PmsSkuInfo getInfo(String spuId) {
        QueryWrapper<PmsSkuInfo> qw = new QueryWrapper<>();
        qw.eq("product_id", spuId);

        return (PmsSkuInfo) this.getOne(qw);

    }


    @Cacheable(value = {"skuAll"}, key = "#productId")
    @Override
    public List<PmsSkuInfo> getAllSku(String productId) {
        return baseMapper.getAllSku(productId);
    }


    @Autowired
    PmsSkuAttrValueService skuAttrValueService;

    // 根据三级分类查出所有sku
    @Override
    public List<PmsSkuInfo> getAllSkuByCatalog3Id(String catalog3Id) {

        // 直接查询出所有,一次性转化
        List<PmsSkuInfo> skus = (List<PmsSkuInfo>) this.list(null);
        // 写入属性
        for (PmsSkuInfo pmsSkuInfo : skus) {
            String skuId = pmsSkuInfo.getId();

            List<PmsSkuAttrValue> list = (List<PmsSkuAttrValue>) skuAttrValueService.listByMap(MapUtil.of(
                    "sku_id",
                    skuId
                                                                                                         ));
            pmsSkuInfo.setPmsSkuAttrValueList(list);


        }


        return skus;
    }


    @Autowired
    RedisUtil redisUtil;

    @Override
    public boolean checkPrice(String skuId, BigDecimal price) {
        boolean b = false;


        PmsSkuInfo pmsSkuInfo = baseMapper.selectById(skuId);


        if (pmsSkuInfo != null) {
            BigDecimal realPrice = pmsSkuInfo.getPrice();
            if (realPrice != null) {

                int i = realPrice.compareTo(price);
                if (i == 0) {
                    b = true;
                }



            }
        }




        // 数据库数据对不上,直接返回true , 逻辑没问题
        return true;
    }

    @Override
    public PmsSkuInfo getSkuById(String skuId, String ip) {
        System.out.println("ip为" + ip + "的同学:" + Thread.currentThread().getName() + "进入的商品详情的请求");
        PmsSkuInfo pmsSkuInfo = new PmsSkuInfo();
        // 链接缓存
        Jedis jedis = redisUtil.getJedis();
        // 查询缓存
        String skuKey = "sku:" + skuId + ":info";
        String skuJson = jedis.get(skuKey);

        if (StrUtil.isNotBlank(skuJson)) {//if(skuJson!=null&&!skuJson.equals(""))
            System.out.println("ip为" + ip + "的同学:" + Thread.currentThread().getName() + "从缓存中获取商品详情");

            pmsSkuInfo = JSON.parseObject(skuJson, PmsSkuInfo.class);
        } else {
            // 如果缓存中没有，查询mysql
            System.out.println("ip为" + ip + "的同学:" + Thread.currentThread().getName() + "发现缓存中没有，申请缓存的分布式锁：" + "sku:" + skuId + ":lock");

            // 设置分布式锁
            String token = UUID.randomUUID().toString();
            String OK = jedis.set("sku:" + skuId + ":lock", token, "nx", "px", 10 * 1000);// 拿到锁的线程有10秒的过期时间
            if (StrUtil.isNotBlank(OK) && OK.equals("OK")) {
                // 设置成功，有权在10秒的过期时间内访问数据库
                System.out.println("ip为" + ip + "的同学:" + Thread.currentThread().getName() + "有权在10秒的过期时间内访问数据库：" +
                                           "sku:" + skuId + ":lock");

                pmsSkuInfo = this.getInfo(skuId);

                if (pmsSkuInfo != null) {
                    // mysql查询结果存入redis
                    jedis.set("sku:" + skuId + ":info", JSON.toJSONString(pmsSkuInfo));
                } else {
                    // 数据库中不存在该sku
                    // 为了防止缓存穿透将，null或者空字符串值设置给redis
                    jedis.setex("sku:" + skuId + ":info", 60 * 3, JSON.toJSONString(""));
                }

                // 在访问mysql后，将mysql的分布锁释放
                System.out.println("ip为" + ip + "的同学:" + Thread.currentThread().getName() + "使用完毕，将锁归还：" + "sku:" + skuId + ":lock");
                String lockToken = jedis.get("sku:" + skuId + ":lock");
                if (StrUtil.isNotBlank(lockToken) && lockToken.equals(token)) {
                    //jedis.eval("lua");可与用lua脚本，在查询到key的同时删除该key，防止高并发下的意外的发生
                    jedis.del("sku:" + skuId + ":lock");// 用token确认删除的是自己的sku的锁
                }
            } else {
                // 设置失败，自旋（该线程在睡眠几秒后，重新尝试访问本方法）
                System.out.println("ip为" + ip + "的同学:" + Thread.currentThread().getName() + "没有拿到锁，开始自旋");

                return getSkuById(skuId, ip);
            }
        }
        jedis.close();
        // TODO: 2019/12/12  先隐藏真实的缓存逻辑
        // return pmsSkuInfo;

        return this.getById(skuId);
    }


}
